/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:        sqbang                                                 *
 * Email:         sqbang@ustc.edu                                        *
 * Date:          2014.10.12                                             *
 * Description:   diffusion equation ensemble                            *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/equa/HeatConductionEquationEnsemble.h"

//SAMRAI headers
#ifdef FREEMAPS_HAVE_SAMRAI
#  include "SAMRAI/geom/CartesianPatchGeometry.h"
#endif
//LIBMESH headers

//COMMON headers
#include "COMMON/info/InfoManager.h"
#include "COMMON/info/CommonInfo.h"
#include "COMMON/tbox/MathUtilities.h"
#include "COMMON/tbox/LogMessage.h"



namespace FreeMAPs
{

HeatConductionEquationEnsemble::HeatConductionEquationEnsemble (
    const std::string& parent_name,
    const std::string& object_name/*,
    const int sys_id*/):
    Parent (parent_name, object_name/*, sys_id*/),
    d_is_steady (false),
    d_has_decomposite_effection (false),
//    d_var_temperature (nullptr),
//    d_decomposite_factor (nullptr),
    d_use_effect_capacity (false),
    d_coef_name_of_density ("DENSITY"),
    d_coef_name_of_capacity ("CAPACITY"),
    d_coef_name_of_conductance_x ("CONDUCTANCE"),
    d_coef_name_of_conductance_y ("CONDUCTANCE"),
    d_coef_name_of_conductance_z ("CONDUCTANCE"),
//    d_coef_source (0),
    d_init_total_mass (FREEMAPS_INVALID_VALUE)
{
    bool is_un_steady = FreeMAPs::InfoManager::get_instance()->is_un_steady();
    d_is_steady = !is_un_steady;
}



HeatConductionEquationEnsemble::~HeatConductionEquationEnsemble()
{
//    Utilities::clear_pointer_object (d_coef_source);
}



void
HeatConductionEquationEnsemble::get_info_for_derived_object_from_input (
    const InputDatabase* db)
{
    this->prepare_for_use (db);

    db->insert_allowable_key ("is_steady");
    db->insert_allowable_key ("has_decomposite_effection");
    db->insert_allowable_key ("use_effect_capacity");
    db->insert_allowable_key ("var_temperature_name");
    db->insert_allowable_key ("coef_density");
    db->insert_allowable_key ("coef_capacity");
    db->insert_allowable_key ("coef_conductance_x");
    db->insert_allowable_key ("coef_melt_latent_heat");
    db->insert_allowable_key ("coef_melt_temperature_inf");
    db->insert_allowable_key ("coef_melt_temperature_sup");

    db->insert_allowable_key ("coef_conductance_y");
    db->insert_allowable_key ("coef_conductance_z");
    db->insert_allowable_key ("coef_source");

    db->insert_allowable_key ("coef_decomposite_rate");
    db->insert_allowable_key ("var_decomposite_factor_name");

    db->check_allowable_keys();

#if 0
    const VariableInfo* var_info = InfoManager::get_instance()->get_variable_info();
    const FunctionInfo* func_info = InfoManager::get_instance()->get_function_info();
    const CoefficientInfo* coef_info = InfoManager::get_instance()->get_coefficient_info();
#endif
    /*
     * build is_steady
     */
    {
        if( db->key_exists("is_steady") && db->is_bool("is_steady") )
        {
            db->check_optional_key ("is_steady", DataType::BOOL, true, false);
            d_is_steady = db->get_bool_with_default ("is_steady", d_is_steady);
        }
    }

    /*
     * has_decomposite_effection
     */
    {
        if( db->key_exists("has_decomposite_effection") && db->is_bool("has_decomposite_effection") )
        {
            d_has_decomposite_effection = db->get_bool_with_default("has_decomposite_effection", d_has_decomposite_effection);
        }
    }

#if 0
    /*
     * build use_effect_capacity
     */
    {
        db->check_optional_key ("use_effect_capacity", DataType::BOOL, true, false);
        d_use_effect_capacity = db->get_bool_with_default ("use_effect_capacity", d_use_effect_capacity);
    }
    /*
     * build var_temperature
     */
    {
        d_var_temperature = this->get_variable_from_database (
                                db,
                                "var_temperature_name",
                                VariableType::SCALAR);
        FREEMAPS_ASSERT_VALID_POINTER (d_var_temperature);

        d_var_temperature->set_dependency_type (DependencyType::BASE);
        d_var_temperature->attach_equation_ensemble (this);
    }

    /*
    * if simulation composite problem, build decomposite_factor and coef_decomposite_rate_name;
    */
    if (db-> key_exists("var_decomposite_factor_name"))
    {
        d_decomposite_factor = this->get_variable_from_database (
                                   db,
                                   "var_decomposite_factor_name",
                                   VariableType::SCALAR);
        FREEMAPS_ASSERT_VALID_POINTER (d_decomposite_factor);

        d_decomposite_factor->set_dependency_type (DependencyType::DERIVED);
        d_decomposite_factor->attach_equation_ensemble (this);
        d_decomposite_factor->get_variable_data()->set_data_type(VariableDataType::STD_VECTOR);

        {
            db->check_optional_key ("coef_decomposite_rate", DataType::STRING, true, false);
            d_coef_decomposite_rate_name = db->get_string_with_default ("coef_decomposite_rate", d_coef_decomposite_rate_name);
            if (!coef_info->has_coefficient (d_coef_decomposite_rate_name))
            {
                LogMessage::use_improper_string_value (
                    db,
                    "coef_decomposite_rate",
                    d_coef_decomposite_rate_name,
                    "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                    Utilities::get_map_keys (coef_info->get_coefficients()));
            }
            coef_info->get_coefficient (d_coef_decomposite_rate_name)->set_used_flag();
            this->add_key_for_checking_consistence ("coef_decomposite_rate", "check if all region have set the coefficient.");
        }
    }

    if (!d_is_steady)
    {
        /*
         * build coef_density
         */
        {
            db->check_optional_key ("coef_density", DataType::STRING, true, false);
            d_coef_name_of_density = db->get_string_with_default ("coef_density", d_coef_name_of_density);
            if (!coef_info->has_coefficient (d_coef_name_of_density))
            {
                LogMessage::use_improper_string_value (
                    db,
                    "coef_density",
                    d_coef_name_of_density,
                    "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                    Utilities::get_map_keys (coef_info->get_coefficients()));
            }
            coef_info->get_coefficient (d_coef_name_of_density)->set_used_flag();

            this->add_key_for_checking_consistence ("coef_density", "check if all region have set the coefficient.");
        }

        /*
         * build coef_capacity
         */
        {
            db->check_optional_key ("coef_capacity", DataType::STRING, true, false);
            d_coef_name_of_capacity = db->get_string_with_default ("coef_capacity", d_coef_name_of_capacity);
            if (!coef_info->has_coefficient (d_coef_name_of_capacity))
            {
                LogMessage::use_improper_string_value (
                    db,
                    "coef_capacity",
                    d_coef_name_of_capacity,
                    "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                    Utilities::get_map_keys (coef_info->get_coefficients()));
            }
            coef_info->get_coefficient (d_coef_name_of_capacity)->set_used_flag();
            this->add_key_for_checking_consistence ("coef_capacity", "check if all region have set the coefficient.");
        }
    }

    /*
     * build coef_melt
     */
    if(db->key_exists("coef_melt_latent_heat"))
    {
        db->check_optional_key ("coef_melt_latent_heat", DataType::STRING, true, false);
        d_coef_name_of_phase_change_latent_heat = db->get_string_with_default ("coef_melt_latent_heat", d_coef_name_of_phase_change_latent_heat);
        if (!coef_info->has_coefficient (d_coef_name_of_phase_change_latent_heat))
        {
            LogMessage::use_improper_string_value (
                db,
                "coef_melt_latent_heat",
                d_coef_name_of_phase_change_latent_heat,
                "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                Utilities::get_map_keys (coef_info->get_coefficients()));
        }
        coef_info->get_coefficient (d_coef_name_of_phase_change_latent_heat)->set_used_flag();
        this->add_key_for_checking_consistence ("coef_melt_latent_heat", "check if all region have set the coefficient.");
    }

    if(db->key_exists("coef_melt_temperature_inf"))
    {
        db->check_optional_key ("coef_melt_temperature_inf", DataType::STRING, true, false);
        d_coef_name_of_phase_change_temperature_inf = db->get_string_with_default ("coef_melt_temperature_inf", d_coef_name_of_phase_change_temperature_inf);
        if (!coef_info->has_coefficient (d_coef_name_of_phase_change_temperature_inf))
        {
            LogMessage::use_improper_string_value (
                db,
                "coef_melt_temperature_inf",
                d_coef_name_of_phase_change_temperature_inf,
                "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                Utilities::get_map_keys (coef_info->get_coefficients()));
        }
        coef_info->get_coefficient (d_coef_name_of_phase_change_temperature_inf)->set_used_flag();
        this->add_key_for_checking_consistence ("coef_melt_temperature_inf", "check if all region have set the coefficient.");


        db->check_optional_key ("coef_melt_temperature_sup", DataType::STRING, true, false);
        d_coef_name_of_phase_change_temperature_sup = db->get_string_with_default ("coef_melt_temperature_sup", d_coef_name_of_phase_change_temperature_sup);
        if (!coef_info->has_coefficient (d_coef_name_of_phase_change_temperature_sup))
        {
            LogMessage::use_improper_string_value (
                db,
                "coef_melt_temperature_sup",
                d_coef_name_of_phase_change_temperature_sup,
                "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                Utilities::get_map_keys (coef_info->get_coefficients()));
        }
        coef_info->get_coefficient (d_coef_name_of_phase_change_temperature_sup)->set_used_flag();
        this->add_key_for_checking_consistence ("coef_melt_temperature_sup", "check if all region have set the coefficient.");
    }

    /*
     * build coef_conductance_i
     */
    {
        db->check_optional_key ("coef_conductance_x", DataType::STRING, true, false);
        d_coef_name_of_conductance_x = db->get_string_with_default ("coef_conductance_x", d_coef_name_of_conductance_x);
        if (!coef_info->has_coefficient (d_coef_name_of_conductance_x))
        {
            LogMessage::use_improper_string_value (
                db,
                "coef_conductance_x",
                d_coef_name_of_conductance_x,
                "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                Utilities::get_map_keys (coef_info->get_coefficients()));
        }
        coef_info->get_coefficient (d_coef_name_of_conductance_x)->set_used_flag();
        this->add_key_for_checking_consistence ("coef_conductance_x", "check if all region have set the coefficient.");

        /*
         * use d_coef_name_of_conductance_x as default name of y and z.
         * that means, usually the K is isotropic.
         */
        d_coef_name_of_conductance_y = d_coef_name_of_conductance_x;
        d_coef_name_of_conductance_z = d_coef_name_of_conductance_x;

        db->check_optional_key ("coef_conductance_y", DataType::STRING, true, false);
        d_coef_name_of_conductance_y= db->get_string_with_default ("coef_conductance_y", d_coef_name_of_conductance_y);
        if (!coef_info->has_coefficient (d_coef_name_of_conductance_y))
        {
            LogMessage::use_improper_string_value (
                db,
                "coef_conductance_y",
                d_coef_name_of_conductance_y,
                "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                Utilities::get_map_keys (coef_info->get_coefficients()));
        }
        coef_info->get_coefficient (d_coef_name_of_conductance_y)->set_used_flag();
        this->add_key_for_checking_consistence ("coef_conductance_y", "check if all region have set the coefficient.");

        db->check_optional_key ("coef_conductance_z", DataType::STRING, true, false);
        d_coef_name_of_conductance_z= db->get_string_with_default ("coef_conductance_z", d_coef_name_of_conductance_z);
        if (!coef_info->has_coefficient (d_coef_name_of_conductance_z))
        {
            LogMessage::use_improper_string_value (
                db,
                "coef_conductance_z",
                d_coef_name_of_conductance_z,
                "it should be a coefficient name set in:\n\"base_information --> coefficient_info --> coef_names\"",
                Utilities::get_map_keys (coef_info->get_coefficients()));
        }
        coef_info->get_coefficient (d_coef_name_of_conductance_z)->set_used_flag();
        this->add_key_for_checking_consistence ("coef_conductance_z", "check if all region have set the coefficient.");
    }

    /*
     * build coef_source
     */
    {
        db->check_optional_key ("coef_source", DataType::UNKNOWN, true, false);
        if (db->key_exists ("coef_source"))
        {
            if(db->is_string("coef_source") &&InfoManager::get_instance()->get_function_info()->has_function( db->get_string ("coef_source") ) )
            {
                d_coef_source = const_cast<Function*>(InfoManager::get_instance()->get_function_info()->get_function(db->get_string ("coef_source")) );
                d_coef_source->set_used_flag();
            }
            else
            {
                d_coef_source = new Function (this->get_full_name(), "coef_source");
                d_coef_source->get_from_input (
                    db,
                    "coef_source",
                    var_info,
                    func_info);
                d_coef_source->set_used_flag();
            }
        }
    }
#endif
}



std::string
HeatConductionEquationEnsemble::get_info_from_derived_object() const
{
    std::ostringstream os;
    os << "equations\n{\n";

    os << LogMessage::get_prefix (ONE_TAB) << "is_steady  = " << LogMessage::get_bool_string (d_is_steady) << '\n';//use default value -->false
    os << LogMessage::get_prefix (ONE_TAB) << "has_decomposite_effection = " << LogMessage::get_bool_string (d_has_decomposite_effection) << '\n';
#if 0
    os << LogMessage::get_prefix (ONE_TAB) << "use_effect_capacity  = " << LogMessage::get_bool_string (d_use_effect_capacity) << '\n';
//    os << LogMessage::get_prefix (ONE_TAB) << "var_temperature_name = \"" << d_var_temperature->get_name() << "\"\n";
    os << LogMessage::get_prefix (ONE_TAB) << "var_temperature_name = \"" << "TEMPERATURE" << "\"\n";

    if (!d_is_steady)
    {
        os << LogMessage::get_prefix (ONE_TAB) << "coef_density         = \"" << d_coef_name_of_density << "\"\n";
        os << LogMessage::get_prefix (ONE_TAB) << "coef_capacity        = \"" << d_coef_name_of_capacity << "\"\n";
    }

    os << LogMessage::get_prefix (ONE_TAB) << "coef_conductance_x   = \"" << d_coef_name_of_conductance_x << "\"\n";
    os << LogMessage::get_prefix (ONE_TAB) << "coef_melt_latent_heat     = \"" << "MELT_LATENT_HEAT" << "\"\n";
    os << LogMessage::get_prefix (ONE_TAB) << "coef_melt_temperature_sup = \"" << "MELT_POINT_SUP" << "\"\n";
    os << LogMessage::get_prefix (ONE_TAB) << "coef_melt_temperature_inf = \"" << "MELT_POINT_INF" << "\"\n";
    os << LogMessage::get_prefix (ONE_TAB) << "coef_conductance_y   = \"" << d_coef_name_of_conductance_y << "\"\n";
    os << LogMessage::get_prefix (ONE_TAB) << "coef_conductance_z   = \"" << d_coef_name_of_conductance_z << "\"\n";
    if (d_coef_source)
    {
        std::ostringstream oss;
        oss << *d_coef_source;
        os << LogMessage::get_log_info (oss, ONE_TAB) << '\n';
    }
#endif
    os << "}";

    return os.str();
}

} // namespace FreeMAPs
